package com.lmm.rpc.core.cluster;

import com.lmm.rpc.core.util.IpRegexUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @title: DirectClusterImpl
 * @Description: TODO
 * @Author Lmm
 * @Date: 2022/9/29 15:42
 * @Version 1.0
 */
@Slf4j
public class DirectClusterImpl<T> extends AbstractCluster<T>{


    /**
     * 切割符
     * */
    public static final String REGEX = "[^0-9a-zA-Z_\\-\\.:#]+";
    /**
     * ip：port 字符串
     *
     * */
    private String ipsAndPorts;

    /**
     * 服务提供者列表
     * */
    private List<RemoteServerInfo> serverList = new CopyOnWriteArrayList<>();

    public DirectClusterImpl(String ipsAndPorts, ILoadBalancer iLoadBalancer, String serviceName, boolean async, int conTimeOut, int soTimeOut, GenericObjectPoolConfig genericObjectPoolConfig, AbandonedConfig abandonedConfig){
        super(iLoadBalancer,serviceName,async,conTimeOut,soTimeOut,genericObjectPoolConfig,abandonedConfig);
        this.ipsAndPorts = ipsAndPorts;
        this.serviceName = serviceName;
        if (!IpRegexUtil.match(ipsAndPorts)){
            throw new RuntimeException("error expression of ipsAndPorts："+ipsAndPorts + ",serviceName:"+serviceName);
        }
        initServerList();
    }

    /**
     * 因为是本地直连 所以可以直接处理
     *
     * todo 存在的问题:无法感知直连的服务器的情况
     * */
    private void initServerList() {
        if (ipsAndPorts == null)
            return ;
        String[] array = ipsAndPorts.split ( REGEX );
        for (String temp : array) {
            String hostAndIp = temp.split ( "#" )[0].trim ();
            Integer weight = Integer.valueOf (temp.split ( "#" )[1].trim () );
            String host = hostAndIp.split ( ":" )[0].trim ();
            String port = hostAndIp.split ( ":" )[1].trim ();
            String server = "";
            serverList.add (new RemoteServerInfo( host, port, weight, true,server,serviceName));
        }
    }

    @Override
    public void destroy() {
        log.info("ready to shut down【{}】",serviceName);
        serverList = null;
        if (serverPollCache.size() > 0){
            serverPollCache.clear();
        }
    }

    @Override
    public RemoteServerInfo get() {
        return loadBalancer.select(serverList);
    }


    @Override
    public ServerObject<io.netty.channel.Channel> getObjectForRemote() {
        //通过负载均衡获取到可用服务提供者的节点
        RemoteServerInfo remoteServer = this.get();
        if (remoteServer == null)
            return null;
        String remoteSeverKey = createRemoteSeverKey(remoteServer);
        if (serverPollCache.containsKey(remoteSeverKey)){
            return createServerObject(serverPollCache.get(remoteSeverKey),remoteServer);
        }
        //不存在 就创建一个新的资源池
        GenericObjectPool<io.netty.channel.Channel> pool = createGenericObjectPool(remoteServer);
        serverPollCache.put(remoteSeverKey,pool);
        return createServerObject(pool,remoteServer);
    }

    /**
     * 管理remoteServer和对应资源池之间的关系
     * */
    private ServerObject<io.netty.channel.Channel> createServerObject(GenericObjectPool<io.netty.channel.Channel> pool, RemoteServerInfo remoteServer) {
        return new ServerObject<io.netty.channel.Channel>(pool,remoteServer);
    }

    private String createRemoteSeverKey(RemoteServerInfo remoteServer) {
        return remoteServer.getIp().concat("-").concat(remoteServer.getPort());
    }
}
